using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.WebControls;
using System.Data;
using System.ComponentModel;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
using System.Security;

namespace SiteDirectoryWebPart
{
    public class SiteDirectory : System.Web.UI.WebControls.WebParts.WebPart
    {
        #region private variables
        //the managed path to display sites for
        private string _managedPath = string.Empty;
        //the default page size
        private int _pageSize = 0;

        private const int DEFAULT_PAGE_SIZE = 10;

        //the SPGridView to display
        SPGridView spGridView;
        //The datatable that stores the site information
        DataTable dataTableSites;
        //the dataview that supports sorting
        DataView dataViewSites;
        #endregion

        #region Properties
        /// <summary>
        /// The name of the managed path to iterate through sites
        /// </summary>
        [Bindable(true),
        Category("Site Directory Settings"),
        DefaultValue("sites"),
        Localizable(true),
        WebBrowsable(true),
        Personalizable(true),
        WebDescription("Enter the managed path of the sites you want to view."),
        WebDisplayName("Managed Path"),
        WebPartStorage(Storage.Shared),
        FriendlyName("Managed Path"),
        Description("Enter the managed path of the sites you want to view.")]
        public string ManagedPath
        {
            get { return _managedPath; }
            set { _managedPath = value; }
        }

        /// <summary>
        /// This is the property that sets the page size for displaying sites
        /// </summary>
        [Bindable(true),
        Category("Site Directory Settings"),
        DefaultValue(DEFAULT_PAGE_SIZE),
        Localizable(true),
        WebBrowsable(true),
        Personalizable(true),
        WebDescription("Enter the number of sites you want displayed per page."),
        WebDisplayName("Page Size"),
        WebPartStorage(Storage.Shared),
        FriendlyName("Page Size"),
        Description("Enter the number of sites you want displayed per page.")]
        public int PageSize
        {
            get { return _pageSize; }
            set { _pageSize = value; }
        }

        #endregion

        public SiteDirectory()
        {
            this.ExportMode = WebPartExportMode.All;
        }

        /// <summary>
        /// Method to override the CreateChildControls method
        /// </summary>
        protected override void CreateChildControls()
        {
            //call the base method - required
            base.CreateChildControls();

            try
            {
                //create a datatable to store the site collection properties
                //I did this because I kept having LOTS of problems trying to bind the 
                //GridView to a <List>SPGridView
                dataTableSites = BuildSiteListDataTable();

                //Build the dynamic gridview
                BuildGridView();

                //Populate dataTableSites with information from sites
                GetSiteCollections(dataTableSites);

                //instantiate the dataViewSites DataView from dataTableSites
                dataViewSites = new DataView(dataTableSites, string.Empty, "SiteName", DataViewRowState.CurrentRows);

                // We have an active sorting, so this need to be preserved
                dataViewSites.Sort = this.SortExpression + " " + this.SortDirection;

                //Bind the spGridView to the DataView
                spGridView.DataSource = dataViewSites;

                //add the SPGridView to the page controls
                Controls.Add(spGridView);

                //set the spGridView.PagerTemplate = null AFTER Controls.Add(spGridView)
                //  otherwise, we might get a NullReference exception
                spGridView.PagerTemplate = null;

                //it's actually important that the databind be 
                // AFTER the spGridView is added to the controls
                spGridView.DataBind();
            }
            catch (Exception ex)
            {
                //If there's an exception, create a label to display it
                Label lblErrorMessage = new Label();
                lblErrorMessage.Text = "An error has occurred: ";
                lblErrorMessage.Text += ex.Message;

                if (ex.InnerException != null)
                {
                    lblErrorMessage.Text += Environment.NewLine + "Inner Exception: " + ex.InnerException.Message;
                }
                Controls.Add(lblErrorMessage);
            }
        }

        /// <summary>
        /// I had lots of issues trying to bind the list of SPSites to a gridview, 
        ///   so I've created a datatable to hold values.
        /// </summary>
        /// <returns></returns>
        private DataTable BuildSiteListDataTable()
        {
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add("SiteName");
            dataTable.Columns.Add("SiteUrl");
            dataTable.Columns.Add("SiteDescription");
            dataTable.Columns.Add("PrimaryOwnerId");
            dataTable.Columns.Add("PrimaryOwnerName");
            dataTable.Columns.Add("SecondaryOwnerId");
            dataTable.Columns.Add("SecondaryOwnerName");
            dataTable.Columns.Add("SiteUsage");
            dataTable.Columns.Add("SiteVisits");

            return dataTable;
        }

        /// <summary>
        /// This method adds columns to the SPGridView
        /// </summary>
        public void BuildGridView()
        {
            spGridView = new SPGridView();
            spGridView.AutoGenerateColumns = false;
            spGridView.AllowSorting = true;
            spGridView.AllowPaging = true;
            spGridView.PagerSettings.Mode = PagerButtons.NumericFirstLast;
            spGridView.PagerTemplate = null;
            spGridView.PageSize = _pageSize;
            spGridView.Columns.Clear();

            //bind the event handlers for sorting and paging
            spGridView.Sorting += new GridViewSortEventHandler(spGridView_Sorting);
            spGridView.PageIndexChanging += new GridViewPageEventHandler(spGridView_PageIndexChanging);

            SPMenuField colMenu = new SPMenuField();
            colMenu.HeaderText = "Site Name";
            colMenu.TextFields = "SiteName";
            colMenu.MenuTemplateId = "SiteListMenu";
            colMenu.NavigateUrlFields = "SiteUrl, SiteName";
            colMenu.NavigateUrlFormat = "{0}";
            colMenu.SortExpression = "SiteName";
            colMenu.TokenNameAndValueFields = "URL=SiteUrl,NAME=SiteName";
            colMenu.MenuFormat = MenuFormat.ArrowOnHover;

            MenuTemplate itemListMenu = new MenuTemplate();
            itemListMenu.ID = "SiteListMenu";
            MenuItemTemplate menu = new MenuItemTemplate("Add to favorites", "_layouts/images/addtofavorites.gif");
            menu.ClientOnClickScript = "javascript:window.external.addFavorite(\"%URL%\",\"%NAME%\");";

            itemListMenu.Controls.Add(menu);
            this.Controls.Add(itemListMenu);
            spGridView.Columns.Add(colMenu);

            //if I have a chance, I'd like to replace the add to favorites button with a 'add to my sites'
            // button

            //site name
            //HyperLinkField hlnkColumn = new HyperLinkField();
            //hlnkColumn.HeaderText = "Site Name";
            //hlnkColumn.DataTextField = "SiteName";
            //hlnkColumn.SortExpression = "SiteName";
            //hlnkColumn.DataNavigateUrlFields = new string[] { "SiteUrl" };
            //hlnkColumn.DataNavigateUrlFormatString = "{0}";
            //spGridView.Columns.Add(hlnkColumn);

            //primary owner
            HyperLinkField hlnkColumn = new HyperLinkField();
            hlnkColumn.HeaderText = "Primary Owner";
            hlnkColumn.DataTextField = "PrimaryOwnerName";
            hlnkColumn.SortExpression = "PrimaryOwnerName";
            hlnkColumn.DataNavigateUrlFields = new string[] { "PrimaryOwnerId" };
            hlnkColumn.DataNavigateUrlFormatString = "http://mysiteurl/Person.aspx?accountname={0}";
            spGridView.Columns.Add(hlnkColumn);

            //secondary owner
            hlnkColumn = new HyperLinkField();
            hlnkColumn.HeaderText = "Secondary Owner";
            hlnkColumn.DataTextField = "SecondaryOwnerName";
            hlnkColumn.SortExpression = "SecondaryOwnerName";
            hlnkColumn.DataNavigateUrlFields = new string[] { "SecondaryOwnerId" };
            hlnkColumn.DataNavigateUrlFormatString = "http://mysiteurl/Person.aspx?accountname={0}";
            spGridView.Columns.Add(hlnkColumn);

            //storage used
            BoundField boundField = new BoundField();
            boundField.HeaderText = "Storage Used (MB)";
            boundField.DataField = "SiteUsage";
            boundField.SortExpression = "SiteUsage";
            spGridView.Columns.Add(boundField);
        }

        /// <summary>
        /// This method gets a list of all site collections within the manage path specified
        /// </summary>
        /// <returns></returns>
        private void GetSiteCollections(DataTable dataTableSitesList)
        {
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    SPWebApplication webApp = SPControl.GetContextWebApplication(Context);

                    if (webApp != null)
                    {
                        foreach (SPSite siteCollection in webApp.Sites)
                        {
                            try
                            {
                                if (!siteCollection.ReadLocked && !siteCollection.ReadOnly)
                                {
                                    string[] splitUrl = siteCollection.ServerRelativeUrl.Split(new char[] { '/' });

                                    if (splitUrl.Length >= 2)
                                    {
                                        if (splitUrl[1] == _managedPath)
                                        {
                                            //create a new datarow and assign values from the site
                                            // collection to the row cells
                                            DataRow dataRow = dataTableSitesList.NewRow();
                                            dataRow["SiteName"] = siteCollection.RootWeb.Title;
                                            dataRow["SiteUrl"] = siteCollection.Url;
                                            dataRow["SiteDescription"] = siteCollection.RootWeb.Description;
                                            dataRow["PrimaryOwnerId"] = siteCollection.Owner.LoginName;
                                            dataRow["PrimaryOwnerName"] = siteCollection.Owner.Name;


                                            if (siteCollection.SecondaryContact != null)
                                            {
                                                dataRow["SecondaryOwnerId"] = siteCollection.SecondaryContact.LoginName;
                                                dataRow["SecondaryOwnerName"] = siteCollection.SecondaryContact.Name;
                                            }

                                            dataRow["SiteUsage"] = siteCollection.Usage.Storage / (1024 * 1024);
                                            dataRow["SiteVisits"] = siteCollection.Usage.Visits;
                                            dataTableSitesList.Rows.Add(dataRow);
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                string temp = ex.Message;
                                //Possible use of notification services to notify of error
                                //for now swallow the error.
                                //Putting this in here because of the locked sites throwing
                                //an error when accessed.
                            }

                            //ALWAYS dispose of site collections
                            siteCollection.Dispose();
                        }
                    }
                });
            }
            catch (SecurityException ex)
            {
                Label lblMessage = new Label();
                lblMessage.Text = ex.Message;
                Controls.Add(lblMessage);
            }
        }

        /// <summary>
        /// The event handler for sorting the grid
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void spGridView_Sorting(object sender, GridViewSortEventArgs e)
        {
            string lastExpression = "";
            if (this.SortExpression != null)
                lastExpression = this.SortExpression;

            string lastDirection = "asc";
            if (this.SortDirection != null)
                lastDirection = this.SortDirection;

            string newDirection = "asc";
            if (e.SortExpression == lastExpression)
                newDirection = (lastDirection == "asc") ? "desc" : "asc";

            this.SortExpression = e.SortExpression;
            this.SortDirection = newDirection;

            dataViewSites.Sort = e.SortExpression + " " + newDirection;

            spGridView.PagerTemplate = null;
            spGridView.DataBind();
        }

        /// <summary>
        /// The event handler for paging
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void spGridView_PageIndexChanging(object sender, GridViewPageEventArgs e)
        {
            spGridView.PageIndex = e.NewPageIndex;
            spGridView.PagerTemplate = null;
            spGridView.DataBind();
        }

        /// <summary>
        /// The sort expression as stored in the viewstate
        /// </summary>
        private string SortExpression
        {
            get
            {
                if (ViewState["SortExpression"] != null)
                {
                    return ViewState["SortExpression"].ToString();
                }
                else
                {
                    ViewState["SortExpression"] = "SiteName";
                    return ViewState["SortExpression"].ToString();
                }
            }
            set
            {
                ViewState["SortExpression"] = value;
            }
        }

        /// <summary>
        /// the sort direction as stored in the viewstate
        /// </summary>
        private string SortDirection
        {
            get
            {
                if (ViewState["SortDirection"] != null)
                {
                    return ViewState["SortDirection"].ToString();
                }
                else
                {
                    ViewState["SortDirection"] = "asc";
                    return ViewState["SortDirection"].ToString();
                }
            }
            set
            {
                ViewState["SortDirection"] = value;
            }
        }

    }
}
